﻿using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Json;
using System.Xml.Serialization;

using XNET.Extension;

namespace XNET.IO
{
    /// <summary>
    /// 序列化辅助类
    /// </summary>
    public class XSerialize
    {
        /// <summary>
        /// 对象序列化到文件
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="data">数据</param>
        /// <param name="fileName">文件名</param>
        /// <param name="type">序列化类型</param>
        public static void SerializeToFile<T>(T data, string fileName, SerializationTypeEnum type = SerializationTypeEnum.Binary)
        {
            var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
            try
            {
                switch (type)
                {
                    case SerializationTypeEnum.Binary:
                        var binarySerializer = new BinaryFormatter();
                        binarySerializer.Serialize(fs, data);
                        break;
                    case SerializationTypeEnum.DataContract:
                        var dataContractSerialize = new DataContractSerializer(typeof(T));
                        dataContractSerialize.WriteObject(fs, data);
                        break;
                    case SerializationTypeEnum.Json:
                        var dataContractJsonSerializer = new DataContractJsonSerializer(typeof(T));
                        dataContractJsonSerializer.WriteObject(fs, data);
                        break;
                    case SerializationTypeEnum.Xml:
                        var xmlSerializer = new XmlSerializer(typeof(T));
                        xmlSerializer.Serialize(fs, data);
                        break;
                }
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }
        }

        /// <summary>
        /// 文件反序列化到对象
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="fileName">文件路径</param>
        /// <param name="type">序列化类型</param>
        /// <returns></returns>
        public static T DeserializeFromFile<T>(string fileName, SerializationTypeEnum type = SerializationTypeEnum.Binary)
        {
            if (!System.IO.File.Exists(fileName))
            {
                return default(T);
            }
            var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            try
            {
                object obj = null;
                switch (type)
                {
                    case SerializationTypeEnum.Binary:
                        var binarySerializer = new BinaryFormatter();
                        obj = binarySerializer.Deserialize(fs);
                        break;
                    case SerializationTypeEnum.DataContract:
                        var dataContractSerialize = new DataContractSerializer(typeof(T));
                        obj = dataContractSerialize.ReadObject(fs);
                        break;
                    case SerializationTypeEnum.Json:
                        var dataContractJsonSerializer = new DataContractJsonSerializer(typeof(T));
                        obj = dataContractJsonSerializer.ReadObject(fs);
                        break;
                    case SerializationTypeEnum.Xml:
                        var xmlSerializer = new XmlSerializer(typeof(T));
                        obj = xmlSerializer.Deserialize(fs);
                        break;
                }
                return (T)obj;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }
        }

        /// <summary>
        /// 序列化到字符
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="data">数据</param>
        /// <param name="type">序列化类型</param>
        /// <returns></returns>
        public static string Serialize<T>(T data, SerializationTypeEnum type = SerializationTypeEnum.Binary)
        {
            var bytes = SerializeToByte<T>(data, type);

            if (bytes.IsNullOrEmpty())
            {
                return string.Empty;
            }
            else
            {
                return System.Convert.ToBase64String(bytes);
            }
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="sStr">序列化字符</param>
        /// <param name="type">序列化类型</param>
        /// <returns></returns>
        public static T Deserialize<T>(string sStr, SerializationTypeEnum type = SerializationTypeEnum.Binary)
        {
            return DeserializeFromByte<T>(System.Convert.FromBase64String(sStr), type);
        }

        /// <summary>
        /// 序列化到字节
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="data">数据</param>
        /// <param name="type">序列化类型</param>
        /// <returns></returns>
        public static byte[] SerializeToByte<T>(T data, SerializationTypeEnum type = SerializationTypeEnum.Binary)
        {
            if (data == null)
            {
                return null;
            }
            using (var stream = new MemoryStream())
            {
                switch (type)
                {
                    case SerializationTypeEnum.Binary:
                        var binarySerializer = new BinaryFormatter();
                        binarySerializer.Serialize(stream, data);
                        break;
                    case SerializationTypeEnum.DataContract:
                        var dataContractSerializer = new DataContractSerializer(typeof(T));
                        dataContractSerializer.WriteObject(stream, data);
                        break;
                    case SerializationTypeEnum.Json:
                        var dataContractJsonSerializer = new DataContractJsonSerializer(typeof(T));
                        dataContractJsonSerializer.WriteObject(stream, data);
                        break;
                    case SerializationTypeEnum.Xml:
                        var xmlSerialize = new XmlSerializer(typeof(T));
                        xmlSerialize.Serialize(stream, data);
                        break;
                }
                return stream.ToArray();
            }
        }

        /// <summary>
        /// 反序列化到对象
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="bytes">字节</param>
        /// <param name="type">序列化类型</param>
        /// <returns></returns>
        public static T DeserializeFromByte<T>(byte[] bytes, SerializationTypeEnum type = SerializationTypeEnum.Binary)
        {
            if (bytes.IsNullOrEmpty())
            {
                return default(T);
            }
            using (var stream = new MemoryStream(bytes))
            {
                object obj = null;
                switch (type)
                {
                    case SerializationTypeEnum.Binary:
                        var binarySerializer = new BinaryFormatter();
                        obj = binarySerializer.Deserialize(stream);
                        break;
                    case SerializationTypeEnum.DataContract:
                        var dataContractSerializer = new DataContractSerializer(typeof(T));
                        obj = dataContractSerializer.ReadObject(stream);
                        break;
                    case SerializationTypeEnum.Json:
                        var dataContractJsonSerializer = new DataContractJsonSerializer(typeof(T));
                        obj = dataContractJsonSerializer.ReadObject(stream);
                        break;
                    case SerializationTypeEnum.Xml:
                        var xmlSerialize = new XmlSerializer(typeof(T));
                        obj = xmlSerialize.Deserialize(stream);
                        break;
                }
                return (T)obj;
            }
        }

        /// <summary>
        /// 将对象使用二进制格式序列化成byte数组
        /// </summary>
        /// <param name="obj">待保存的对象</param>
        /// <returns>byte数组</returns>
        public static byte[] SaveToBinaryBytes(object obj)
        {
            using (var ms = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(ms, obj);

                return ms.ToArray();
            }
        }

        /// <summary>
        /// 将使用二进制格式保存的byte数组反序列化成对象
        /// </summary>
        /// <param name="bytes">byte数组</param>
        /// <returns>对象</returns>
        public static object LoadFromBinaryBytes(byte[] bytes)
        {
            object result = null;

            if (bytes != null)
            {
                using (var ms = new MemoryStream(bytes))
                {
                    var formatter = new BinaryFormatter();
                    result = formatter.Deserialize(ms);
                }
            }
            return result;
        }
    }

    /// <summary>
    /// 序列化类型
    /// </summary>
    public enum SerializationTypeEnum
    {
        /// <summary>
        /// XML格式
        /// </summary>
        Xml,
        /// <summary>
        /// JSON格式
        /// </summary>
        Json,
        /// <summary>
        /// WCF数据格式
        /// </summary>
        DataContract,
        /// <summary>
        /// 二进制
        /// </summary>
        Binary
    }
}
